package com.yami.shop.app.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yami.shop.app.config.PayConfig;
import com.yami.shop.app.config.PushMessageUtil;
import com.yami.shop.app.utils.HttpResult;
import com.yami.shop.bean.app.dto.ShopCartOrderMergerDto;
import com.yami.shop.bean.dto.PaymentDto;
import com.yami.shop.bean.enums.OrderStatus;
import com.yami.shop.bean.model.*;
import com.yami.shop.bean.pay.Records;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.security.util.SecurityUtils;
import com.yami.shop.service.*;
import io.swagger.annotations.Api;
import lombok.AllArgsConstructor;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yami.shop.service.ShopDetailService;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.UUID;

@RestController
@RequestMapping("/app/pay")
@Api(tags = "订单接口")
@Component
@PropertySource("classpath:application.yml")
@ConfigurationProperties(prefix = "app")
public class PayController {

    //private final  PayConfig payConfig;

    private  static String authorization;

    @Value("${appId}")
    private String appId;

    @Value("${appKey}")
    private  String appKey;

    @Value("${merchantCode}")
    private String merchantCode; //商户号

    @Value("${terminalCode}")
    private String terminalCode; //终端号;

    @Value("${payUrl}")
    private String payUrl;//支付接口

    @Autowired
    private UmsPayInformationService umsPayInformationService;

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserService userService;

    @Autowired
    private OrderItemService orderItemService;

    @Autowired
    private OldUserService oldUserService;
    @Autowired
    private ShopDetailService shopDetailService;

    /**
     * 请求支付 payType(1.现金 2.扫码 3.账户支付)
     */
    @PostMapping("/payment")
    public HttpResult payment(@RequestBody PaymentDto paymentDto) throws Exception {
        String result = null;
        String payCode = paymentDto.getPayCode();
        String payType = paymentDto.getPayType();
        String orderNumber = paymentDto.getOrderNumber();
        Double payMoney = paymentDto.getPayMoney();
        BigDecimal actualCollection = paymentDto.getActualCollection();
        Order corder = orderService.getOrderByOrderNumber(orderNumber);
        ShopDetail shopDetail = shopDetailService.getShopDetailByShopId(corder.getShopId());
        if(payType.equals("1")){
            //支付成功,修改订单状态
            orderService.paySuccessByCash(actualCollection,orderNumber);
            PageParam<Order> page = new PageParam<Order>();
            //返回订单数据
            IPage<Order> orderList = orderService.page(page,
                    new LambdaQueryWrapper<Order>()
                            .eq(Order::getOrderNumber,orderNumber));
            //查询子订单数据
            List<OrderItem> orderItemList = orderItemService.getOrderItemsByOrderNumber(orderNumber);
            if(CollectionUtils.isNotEmpty(orderItemList)){
                for(Order order:orderList.getRecords()){
                    order.setOrderItems(orderItemList);
                }
            }
            return  HttpResult.success(orderList);
        }else if(payType.equals("2")){
            if(corder!=null){
                int payment = corder.getMixedPayment();
                BigDecimal oldAccount = corder.getOldAccountPay();
                BigDecimal newAccoount = corder.getNewAccountPay();
                if(payment==1){
                    //计算订单剩余的金额
                    if(null!=oldAccount&&oldAccount.compareTo(new BigDecimal("0"))>-1){
                        payMoney = Arith.sub(corder.getActualTotal(),corder.getOldAccountPay().doubleValue());
                    }

                    if(null!=newAccoount&&newAccoount.compareTo(new BigDecimal("0"))>-1){
                        payMoney =Arith.sub(corder.getActualTotal(),corder.getNewAccountPay().doubleValue());
                    }

                }
            }
            result=payV2(orderNumber,payCode,payMoney);

            System.out.println("result"+result);
            umsPayInformationService.dealPaySuccess(result, orderNumber);

            //支付成功,向设备返回支付成功的消息
            String cid = corder.getCid();
            try {
                PushMessageUtil.pushToSingleByCid(cid,orderNumber);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            return HttpResult.success(result);
        }else if(payType.equals("3")){
            //使用账户支付,优先使用老账户支付,当老账户的余额不足的时候,再使用新的账户进行支付
            String payResult = userService.payMoneyByAccount(orderNumber,payMoney);
            Order order = orderService.getOrderByOrderNumber(orderNumber);
            String userId = order.getUserId();
            User user = userService.getUserByUserId(userId);
            Long shopId = order.getShopId();
            OldUser oldUser = oldUserService.getOldUserByShopId(userId,shopId);
            if(oldUser!=null){
                BigDecimal account = oldUser.getAccount();
                user.setOldAccount(account.doubleValue());
            }
            if("success".equals(payResult)){
                return HttpResult.success(user);
            }else{
                return HttpResult.failure(payResult);
            }
        }else{
            return HttpResult.success();
        }


     //   return HttpResult.success(orderList);
    }

    /**
     * 补零
     */
    @PostMapping("/bucha")
    public HttpResult  bucha(@RequestBody PaymentDto paymentDto ){
        //修改用户账户余额
        userService.updateUserAccountByBuCha(paymentDto);
        String orderNumber = paymentDto.getOrderNumber();
        List<OrderItem> orderItemList = orderItemService.getOrderItemsByOrderNumber(orderNumber);
        Order order = orderService.getOrderByOrderNumber(orderNumber);
        ShopCartOrderMergerDto shopCartOrderMergerDto = new ShopCartOrderMergerDto();
        shopCartOrderMergerDto.setActualTotal(order.getActualTotal());
        shopCartOrderMergerDto.setTotalCount(order.getProductNums());
        shopCartOrderMergerDto.setOrderNumber(orderNumber);
        Records record = new Records();
        record.setShopId(order.getShopId());
        record.setOrderNumber(orderNumber);
        // 订单商品名称
        record.setProdName(order.getProdName());
        // 用户id
        record.setUserId(order.getUserId());
        // 商品总额
        record.setTotal(order.getActualTotal());
        // 实际总额
        // order1.setActualTotal(totalPrice);
        record.setStatus(OrderStatus.UNPAY.value());
        record.setUpdateTime(new Date());
        record.setCreateTime(new Date());
        record.setIsPayed(0);
        record.setDeleteStatus(0);
        record.setProductNums(order.getProductNums());
        record.setOrderItems(orderItemList);
        record.setCashier(order.getCashier());
        record.setCid(order.getCid());
        record.setActualTotal(order.getActualTotal());
        record.setMixedPayment(order.getMixedPayment());

        shopCartOrderMergerDto.setRecords(record);
        return  HttpResult.success(shopCartOrderMergerDto);
    }


    /**
     * 进行pos通支付操作,整理参数
     * 接口地址:
     * 测试环境：http://58.247.0.18:29015/v2/poslink/transaction/pay
     * 生产环境：https://api-mop.chinaums.com/v2/poslink/transaction/pay
     */
    public  String payV2(String orderNumber,String payCode,Double payMoney) throws Exception {
        /* post参数,格式:JSON */
        JSONObject body = new JSONObject();
        Order order = orderService.getOrderByOrderNumber(orderNumber);
        body.put("merchantCode", merchantCode);   // 商户号
        body.put("terminalCode", terminalCode);   // 终端号
        if(order!=null) {
            //body.put("transactionAmount", Arith.mul(order.getActualTotal(),100));  // 交易金额,遇到传goods的情况,得算出来
            body.put("transactionAmount",Arith.mul(payMoney,100));
        }
        body.put("transactionCurrencyCode", "156"); // 交易币种
        body.put("merchantOrderId", orderNumber);  // 商户订单号,自定义
        body.put("merchantRemark", "商户备注"); // 商户备注
        body.put("payMode", "CODE_SCAN");    // 支付方式:    E_CASH(电子现金) SOUNDWAVE(声波) NFC(NFC) CODE_SCAN(扫码) MANUAL(手输)
        body.put("payCode", payCode); // 这里需要真实的支付码eg:286656579659199426
        body.put("srcReserved", "商户冗余信息|aabb|cc");  // 商户冗余信息
        //body.put("orderDesc", "账单描述");
        //String url = "http://58.247.0.18:29015/v2/poslink/transaction/pay";
        String send = send(payUrl, body.toString());
        return send;
    }

    /**
     * 发送请求
     *
     * @param url    eg:http://58.247.0.18:29015/v2/poslink/transaction/pay
     * @param entity eg:{"merchantCode":"123456789900081","terminalCode":"00810001","transactionAmount":1,"transactionCurrencyCode":"156","merchantOrderId":"201905211550526234902343","merchantRemark":"商户备注","payMode":"CODE_SCAN","payCode":"285059979526414634"}
     * @return
     * @throws Exception
     */
    public  String send(String url, String entity) throws Exception {
        authorization = getOpenBodySig(appId, appKey, entity);
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Authorization", authorization);
        StringEntity se = new StringEntity(entity, "UTF-8");
        se.setContentType("application/json");
        httpPost.setEntity(se);
        CloseableHttpResponse response = httpClient.execute(httpPost);
        HttpEntity entity1 = response.getEntity();
        String resStr = null;
        if (entity1 != null) {
            resStr = EntityUtils.toString(entity1, "UTF-8");
            System.out.println("返回的结果为"+resStr);
        }
        httpClient.close();
        response.close();
        return resStr;
    }

    /**
     * open-body-sig方式获取到Authorization 的值
     *
     * @param appId  f0ec96ad2c3848b5b810e7aadf369e2f
     * @param appKey 775481e2556e4564985f5439a5e6a277
     * @param body   json字符串 String body = "{\"merchantCode\":\"123456789900081\",\"terminalCode\":\"00810001\",\"merchantOrderId\":\"20123333644493200\",\"transactionAmount\":\"1\",\"merchantRemark\":\"测试\",\"payMode\":\"CODE_SCAN\",\"payCode\":\"285668667587422761\",\"transactionCurrencyCode\":\"156\"}";
     * @return
     * @throws Exception
     */
    public static String getOpenBodySig(String appId, String appKey, String body) throws Exception {
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());   // eg:20190227113148
        String nonce = UUID.randomUUID().toString().replace("-", ""); // eg:be46cd581c9f46ecbd71b9858311ea12
        byte[] data = body.getBytes("UTF-8");
        System.out.println("data:\n" + body);
        InputStream is = new ByteArrayInputStream(data);
        String bodyDigest = testSHA256(is);
        System.out.println("bodyDigest:\n" + bodyDigest);
        String str1_C = appId + timestamp + nonce + bodyDigest;
        byte[] localSignature = hmacSHA256(str1_C.getBytes(), appKey.getBytes());
        String localSignatureStr = Base64.encodeBase64String(localSignature);   // Signature
        System.out.println("Authorization:\n" + "OPEN-BODY-SIG AppId=" + "\"" + appId + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce=" + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\"\n");
        return ("OPEN-BODY-SIG AppId=" + "\"" + appId + "\"" + ", Timestamp=" + "\"" + timestamp + "\"" + ", Nonce=" + "\"" + nonce + "\"" + ", Signature=" + "\"" + localSignatureStr + "\"");
    }

    /**
     * 进行加密
     *
     * @param is
     * @return 加密后的结果
     */
    private static String testSHA256(InputStream is) {
        try {
            return DigestUtils.sha256Hex(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     *
     *
     * @param data
     * @param key
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     */
    public static byte[] hmacSHA256(byte[] data, byte[] key) throws NoSuchAlgorithmException, InvalidKeyException {
        String algorithm = "HmacSHA256";
        Mac mac = Mac.getInstance(algorithm);
        mac.init(new SecretKeySpec(key, algorithm));
        return mac.doFinal(data);
    }


}
